FastAPI OAuth2 ഓതന്റിക്കേഷൻ പഠിക്കൂ! പാസ്വേഡ്, ഇംപ്ലിസിറ്റ്, ഓതറൈസേഷൻ കോഡ് ഫ്ലോകൾ, ടോക്കൺ റിഫ്രഷ്, മികച്ച സുരക്ഷാ സമ്പ്രദായങ്ങൾ എന്നിവ ഈ ഗൈഡിൽ വിശദീകരിക്കുന്നു.
FastAPI OAuth2 നടപ്പിലാക്കൽ: ഒരു സമഗ്രമായ ഓതന്റിക്കേഷൻ ഫ്ലോ ഗൈഡ്
ഇന്നത്തെ ഡിജിറ്റൽ ലോകത്ത്, നിങ്ങളുടെ API-കൾ സുരക്ഷിതമാക്കേണ്ടത് അത്യാവശ്യമാണ്. OAuth2 (ഓപ്പൺ ഓതറൈസേഷൻ) ഡെലിഗേറ്റഡ് ഓതറൈസേഷന്റെ വ്യവസായ മാനദണ്ഡമായി മാറിയിരിക്കുന്നു, ഇത് ഉപയോക്താക്കൾക്ക് അവരുടെ ക്രെഡൻഷ്യലുകൾ പങ്കിടാതെ അവരുടെ വിഭവങ്ങളിലേക്ക് പരിമിതമായ പ്രവേശനം അനുവദിക്കുന്നു. ആധുനികവും ഉയർന്ന പ്രകടനമുള്ളതുമായ ഒരു പൈത്തൺ വെബ് ഫ്രെയിംവർക്കായ FastAPI, OAuth2 ഓതന്റിക്കേഷൻ നടപ്പിലാക്കുന്നത് വളരെ എളുപ്പമാക്കുന്നു. ഈ സമഗ്രമായ ഗൈഡ് വിവിധ OAuth2 ഫ്ലോകളിലൂടെ നിങ്ങളെ നയിക്കുകയും അവ നിങ്ങളുടെ FastAPI ആപ്ലിക്കേഷനിൽ എങ്ങനെ സംയോജിപ്പിക്കാമെന്ന് കാണിക്കുകയും ചെയ്യും, ഇത് നിങ്ങളുടെ API സുരക്ഷിതവും ആക്സസ് ചെയ്യാവുന്നതുമാണെന്ന് ഉറപ്പാക്കുന്നു.
OAuth2 ആശയങ്ങൾ മനസ്സിലാക്കുന്നു
കോഡിലേക്ക് കടക്കുന്നതിന് മുമ്പ്, OAuth2-ന്റെ പ്രധാന ആശയങ്ങൾ വ്യക്തമായി മനസ്സിലാക്കാം:
- വിഭവ ഉടമ: ഡാറ്റയുടെ ഉടമയായ, ആക്സസ് അനുവദിക്കുന്ന ഉപയോക്താവ്.
- ക്ലയിന്റ്: വിഭവ ഉടമയുടെ ഡാറ്റയിലേക്ക് ആക്സസ് അഭ്യർത്ഥിക്കുന്ന ആപ്ലിക്കേഷൻ. ഇത് ഒരു വെബ് ആപ്ലിക്കേഷനോ, മൊബൈൽ ആപ്പോ, മറ്റ് ഏതെങ്കിലും സേവനമോ ആകാം.
- ഓതറൈസേഷൻ സെർവർ: വിഭവ ഉടമയെ ഓതന്റിക്കേറ്റ് ചെയ്യുകയും ക്ലയിന്റിന് ഓതറൈസേഷൻ നൽകുകയും ചെയ്യുന്നു.
- വിഭവ സെർവർ: സംരക്ഷിത വിഭവങ്ങൾ ഹോസ്റ്റ് ചെയ്യുകയും ആക്സസ് അനുവദിക്കുന്നതിന് മുമ്പ് ആക്സസ് ടോക്കൺ പരിശോധിക്കുകയും ചെയ്യുന്നു.
- ആക്സസ് ടോക്കൺ: വിഭവ ഉടമ ക്ലയിന്റിന് നൽകിയ ഓതറൈസേഷനെ പ്രതിനിധീകരിക്കുന്ന ഒരു ക്രെഡൻഷ്യൽ.
- റിഫ്രഷ് ടോക്കൺ: വിഭവ ഉടമ വീണ്ടും ഓതറൈസ് ചെയ്യാതെ പുതിയ ആക്സസ് ടോക്കണുകൾ നേടാൻ ഉപയോഗിക്കുന്ന ഒരു ദീർഘകാല ക്രെഡൻഷ്യൽ.
- സ്കോപ്പുകൾ: ക്ലയിന്റ് അഭ്യർത്ഥിക്കുന്ന നിർദ്ദിഷ്ട അനുമതികൾ നിർവചിക്കുന്നു.
OAuth2 ഫ്ലോകൾ: ശരിയായ സമീപനം തിരഞ്ഞെടുക്കുന്നു
OAuth2 നിരവധി ഓതറൈസേഷൻ ഫ്ലോകൾ നിർവചിക്കുന്നു, ഓരോന്നും വ്യത്യസ്ത സാഹചര്യങ്ങൾക്ക് അനുയോജ്യമാണ്. ഏറ്റവും സാധാരണമായ ഫ്ലോകളും അവ എപ്പോൾ ഉപയോഗിക്കണമെന്നതിന്റെ ഒരു വിവരണം ഇവിടെ നൽകുന്നു:
1. പാസ്വേഡ് (വിഭവ ഉടമ പാസ്വേഡ് ക്രെഡൻഷ്യലുകൾ) ഫ്ലോ
വിവരണം: വിഭവ ഉടമയുടെ യൂസർനെയിമും പാസ്വേഡും നൽകി ക്ലയിന്റ് ഓതറൈസേഷൻ സെർവറിൽ നിന്ന് നേരിട്ട് ആക്സസ് ടോക്കൺ നേടുന്നു. ഉപയോഗ കേസുകൾ: ഫസ്റ്റ്-പാർട്ടി മൊബൈൽ ആപ്പുകൾ പോലുള്ള ഉയർന്ന വിശ്വാസ്യതയുള്ള ആപ്ലിക്കേഷനുകൾ. മറ്റ് ഫ്ലോകൾ സാധ്യമല്ലാത്തപ്പോൾ മാത്രമേ ഇത് ഉപയോഗിക്കാവൂ. ഗുണങ്ങൾ: നടപ്പിലാക്കാൻ എളുപ്പം. ദോഷങ്ങൾ: വിഭവ ഉടമയുടെ ക്രെഡൻഷ്യലുകൾ കൈകാര്യം ചെയ്യാൻ ക്ലയിന്റിനെ ആവശ്യപ്പെടുന്നു, ക്ലയിന്റ് അപഹരിക്കപ്പെട്ടാൽ വിവരങ്ങൾ ചോരാനുള്ള സാധ്യത വർദ്ധിപ്പിക്കുന്നു. മറ്റ് ഫ്ലോകളെക്കാൾ സുരക്ഷ കുറവാണ്. ഉദാഹരണം: ഒരു കമ്പനിയുടെ സ്വന്തം മൊബൈൽ ആപ്പ് അവരുടെ ആന്തരിക API ആക്സസ് ചെയ്യുന്നു.
FastAPI-യിലെ നടപ്പിലാക്കൽ:
ആദ്യം, ആവശ്യമായ പാക്കേജുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക:
pip install fastapi uvicorn python-multipart passlib[bcrypt] python-jose[cryptography]
ഇനി, ഒരു അടിസ്ഥാന ഉദാഹരണം ഉണ്ടാക്കാം:
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# Password hashing configuration
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"hashed_password": pwd_context.hash("password123"),
"scopes": ["read", "write"]
}
}
# Function to verify password
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
# Function to create access token
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# OAuth2 endpoint for token generation
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = users.get(form_data.username)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
if not verify_password(form_data.password, user["hashed_password"]):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user["username"], "scopes": user["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer"}
# Dependency to authenticate requests
async def get_current_user(token: str):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = users.get(username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
വിശദീകരണം:
- ഡിപ്പൻഡൻസികൾ: യൂസർനെയിമും പാസ്വേഡും കൈകാര്യം ചെയ്യാൻ ഞങ്ങൾ `fastapi.security.OAuth2PasswordRequestForm` ഉപയോഗിക്കുന്നു.
- പാസ്വേഡ് ഹാഷിംഗ്: പാസ്വേഡുകൾ സുരക്ഷിതമായി ഹാഷ് ചെയ്യാനും പരിശോധിക്കാനും `passlib` ഉപയോഗിക്കുന്നു. പാസ്വേഡുകൾ ഒരിക്കലും പ്ലെയിൻ ടെക്സ്റ്റിൽ സൂക്ഷിക്കരുത്!
- JWT നിർമ്മാണം: JSON വെബ് ടോക്കണുകൾ (JWTs) നിർമ്മിക്കാനും പരിശോധിക്കാനും `python-jose` ഉപയോഗിക്കുന്നു.
- `/token` എൻഡ്പോയിന്റ്: ഈ എൻഡ്പോയിന്റ് ലോഗിൻ പ്രോസസ്സ് കൈകാര്യം ചെയ്യുന്നു. ഇത് യൂസർനെയിമും പാസ്വേഡും സാധൂകരിക്കുന്നു, സാധുവാണെങ്കിൽ, ഒരു ആക്സസ് ടോക്കൺ നിർമ്മിക്കുന്നു.
- `get_current_user` ഡിപ്പൻഡൻസി: ഈ ഫംഗ്ഷൻ ആക്സസ് ടോക്കൺ പരിശോധിക്കുകയും ഉപയോക്താവിനെ വീണ്ടെടുക്കുകയും ചെയ്യുന്നു.
- `/users/me` എൻഡ്പോയിന്റ്: ഇതൊരു സംരക്ഷിത എൻഡ്പോയിന്റാണ്, ഇത് ആക്സസ് ചെയ്യാൻ സാധുവായ ഒരു ആക്സസ് ടോക്കൺ ആവശ്യമാണ്.
2. ഇംപ്ലിസിറ്റ് ഫ്ലോ
വിവരണം: വിഭവ ഉടമ ഓതന്റിക്കേറ്റ് ചെയ്ത ശേഷം ക്ലയിന്റ് ഓതറൈസേഷൻ സെർവറിൽ നിന്ന് നേരിട്ട് ആക്സസ് ടോക്കൺ സ്വീകരിക്കുന്നു. ആക്സസ് ടോക്കൺ URL ഫ്രാഗ്മെന്റിൽ തിരികെ നൽകുന്നു. ഉപയോഗ കേസുകൾ: ക്ലയിന്റ് സീക്രട്ടുകൾ സൂക്ഷിക്കാൻ സാധ്യമല്ലാത്ത സിംഗിൾ-പേജ് ആപ്ലിക്കേഷനുകൾ (SPAs) കൂടാതെ മറ്റ് ബ്രൗസർ അധിഷ്ഠിത ആപ്ലിക്കേഷനുകൾ. ഗുണങ്ങൾ: ബ്രൗസർ അധിഷ്ഠിത ആപ്ലിക്കേഷനുകൾക്ക് ലളിതം. ദോഷങ്ങൾ: ആക്സസ് ടോക്കൺ URL-ൽ വെളിവാകുന്നതിനാൽ മറ്റ് ഫ്ലോകളെക്കാൾ സുരക്ഷ കുറവാണ്. റിഫ്രഷ് ടോക്കൺ നൽകുന്നില്ല. ഉദാഹരണം: ഒരു സോഷ്യൽ മീഡിയ API ആക്സസ് ചെയ്യുന്ന ഒരു JavaScript ആപ്ലിക്കേഷൻ.
FastAPI-യിലെ നടപ്പിലാക്കൽ പരിഗണനകൾ:
FastAPI ഇംപ്ലിസിറ്റ് ഫ്ലോയുടെ ഫ്രണ്ട്എൻഡ് വശങ്ങൾ നേരിട്ട് കൈകാര്യം ചെയ്യുന്നില്ലെങ്കിലും (ഇതൊരു ബാക്കെൻഡ് ഫ്രെയിംവർക്ക് ആയതുകൊണ്ട്), ഓതന്റിക്കേഷൻ ഫ്ലോ കൈകാര്യം ചെയ്യാൻ നിങ്ങൾ React, Vue, അല്ലെങ്കിൽ Angular പോലുള്ള ഒരു ഫ്രണ്ട്എൻഡ് ഫ്രെയിംവർക്ക് ഉപയോഗിക്കും. FastAPI പ്രാഥമികമായി വിഭവ സെർവറായി പ്രവർത്തിക്കും.
ലളിതമാക്കിയ ബാക്കെൻഡ് (FastAPI - വിഭവ സെർവർ) ഉദാഹരണം:
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2AuthorizationCodeBearer
from jose import JWTError, jwt
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"scopes": ["read", "write"]
}
}
# OAuth2 scheme - using AuthorizationCodeBearer for token verification
oauth2_scheme = OAuth2AuthorizationCodeBearer(authorizationUrl="/auth", tokenUrl="/token") # These URLs are handled by the Authorization Server (not this FastAPI app).
# Dependency to authenticate requests
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = users.get(username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
FastAPI ഉപയോഗിച്ചുള്ള ഇംപ്ലിസിറ്റ് ഫ്ലോയുടെ പ്രധാന കാര്യങ്ങൾ:
- ഓതറൈസേഷൻ സെർവറിന്റെ പങ്ക്: യഥാർത്ഥ ഓതറൈസേഷനും ടോക്കൺ വിതരണവും ഒരു പ്രത്യേക ഓതറൈസേഷൻ സെർവറിലാണ് നടക്കുന്നത്. FastAPI ടോക്കൺ സാധൂകരിച്ച് വിഭവ സെർവറായി പ്രവർത്തിക്കുന്നു.
- ഫ്രണ്ട്എൻഡ് കൈകാര്യം ചെയ്യൽ: ഫ്രണ്ട്എൻഡ് ആപ്ലിക്കേഷൻ (ഉദാഹരണത്തിന്, React, Vue) ഓതറൈസേഷൻ സെർവറിലേക്കുള്ള റീഡയറക്ടും, ഉപയോക്തൃ ലോഗിനും, URL ഫ്രാഗ്മെന്റിൽ നിന്ന് ആക്സസ് ടോക്കൺ വീണ്ടെടുക്കുന്നതും കൈകാര്യം ചെയ്യുന്നു.
- സുരക്ഷാ പരിഗണനകൾ: URL-ൽ ആക്സസ് ടോക്കൺ വെളിപ്പെടുത്തുന്നതുകൊണ്ട്, HTTPS ഉപയോഗിക്കുകയും ടോക്കൺ ആയുസ്സ് കുറഞ്ഞതാക്കുകയും ചെയ്യേണ്ടത് അത്യാവശ്യമാണ്. സാധ്യമെങ്കിൽ PKCE-യോടുകൂടിയ ഓതറൈസേഷൻ കോഡ് ഫ്ലോ തിരഞ്ഞെടുത്ത് ഇംപ്ലിസിറ്റ് ഫ്ലോ ഒഴിവാക്കണം.
3. ഓതറൈസേഷൻ കോഡ് ഫ്ലോ
വിവരണം: ക്ലയിന്റ് ആദ്യം ഓതറൈസേഷൻ സെർവറിൽ നിന്ന് ഒരു ഓതറൈസേഷൻ കോഡ് നേടുന്നു, അത് പിന്നീട് ഒരു ആക്സസ് ടോക്കണിനായി കൈമാറ്റം ചെയ്യുന്നു. ഈ ഫ്ലോയിൽ ക്ലയിന്റിൽ നിന്ന് ഓതറൈസേഷൻ സെർവറിലേക്കും തിരിച്ചുമുള്ള ഒരു റീഡയറക്ട് ഉൾപ്പെടുന്നു. ഉപയോഗ കേസുകൾ: ഒരു ക്ലയിന്റ് സീക്രട്ട് സുരക്ഷിതമായി സൂക്ഷിക്കാൻ കഴിയുന്ന വെബ് ആപ്ലിക്കേഷനുകളും മൊബൈൽ ആപ്പുകളും. ഗുണങ്ങൾ: ആക്സസ് ടോക്കൺ ബ്രൗസറിൽ നേരിട്ട് വെളിപ്പെടുത്താത്തതുകൊണ്ട് ഇംപ്ലിസിറ്റ് ഫ്ലോയെക്കാൾ സുരക്ഷിതമാണ്. ദോഷങ്ങൾ: ഇംപ്ലിസിറ്റ് ഫ്ലോയെക്കാൾ നടപ്പിലാക്കാൻ കൂടുതൽ സങ്കീർണ്ണമാണ്. ഉദാഹരണം: ഒരു ഉപയോക്താവിന്റെ Google Drive ഡാറ്റയിലേക്ക് ആക്സസ് അഭ്യർത്ഥിക്കുന്ന ഒരു മൂന്നാം കക്ഷി ആപ്ലിക്കേഷൻ.
PKCE (പ്രൂഫ് കീ ഫോർ കോഡ് എക്സ്ചേഞ്ച്) ഉപയോഗിച്ചുള്ള ഓതറൈസേഷൻ കോഡ് ഫ്ലോ:
ഓതറൈസേഷൻ കോഡ് തടസ്സപ്പെടുത്തുന്നതിനുള്ള സാധ്യത ലഘൂകരിക്കുന്ന ഓതറൈസേഷൻ കോഡ് ഫ്ലോയുടെ ഒരു വിപുലീകരണമാണ് PKCE. ക്ലയിന്റ് ഒരു സീക്രട്ട് സൂക്ഷിക്കാൻ ആവശ്യമില്ലാത്തതുകൊണ്ട് മൊബൈൽ ആപ്പുകൾക്കും SPAS-കൾക്കും ഇത് വളരെ ശുപാർശ ചെയ്യപ്പെടുന്നു.
FastAPI-യിലെ നടപ്പിലാക്കൽ പരിഗണനകൾ: ഇംപ്ലിസിറ്റ് ഫ്ലോയ്ക്ക് സമാനമായി, ഈ ഫ്ലോയിൽ FastAPI പ്രധാനമായും വിഭവ സെർവറായി പ്രവർത്തിക്കും. ഓതന്റിക്കേഷനും ഓതറൈസേഷൻ കോഡ് വിതരണത്തിനും ഒരു പ്രത്യേക ഓതറൈസേഷൻ സെർവർ ഉത്തരവാദിയാണ്.
ലളിതമാക്കിയ ബാക്കെൻഡ് (FastAPI - വിഭവ സെർവർ) ഉദാഹരണം (ഇംപ്ലിസിറ്റ് ഫ്ലോയ്ക്ക് സമാനം):
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2AuthorizationCodeBearer
from jose import JWTError, jwt
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"scopes": ["read", "write"]
}
}
# OAuth2 scheme - using AuthorizationCodeBearer for token verification
oauth2_scheme = OAuth2AuthorizationCodeBearer(authorizationUrl="/auth", tokenUrl="/token") # These URLs are handled by the Authorization Server.
# Dependency to authenticate requests
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = users.get(username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
FastAPI ഉപയോഗിച്ചുള്ള PKCE-യോടുകൂടിയ ഓതറൈസേഷൻ കോഡ് ഫ്ലോയുടെ പ്രധാന കാര്യങ്ങൾ:
- ഓതറൈസേഷൻ സെർവറിന്റെ പങ്ക്: ഓതറൈസേഷൻ കോഡ് ഉണ്ടാക്കുന്നതും, PKCE കോഡ് വെരിഫയർ പരിശോധിക്കുന്നതും, ആക്സസ് ടോക്കൺ വിതരണം ചെയ്യുന്നതും ഓതറൈസേഷൻ സെർവർ കൈകാര്യം ചെയ്യുന്നു.
- ഫ്രണ്ട്എൻഡ് കൈകാര്യം ചെയ്യൽ: ഫ്രണ്ട്എൻഡ് ആപ്ലിക്കേഷൻ ഒരു കോഡ് വെരിഫയറും കോഡ് ചലഞ്ചും ഉണ്ടാക്കുകയും, ഉപയോക്താവിനെ ഓതറൈസേഷൻ സെർവറിലേക്ക് റീഡയറക്ട് ചെയ്യുകയും, ഓതറൈസേഷൻ കോഡ് സ്വീകരിക്കുകയും, അതിനെ ഒരു ആക്സസ് ടോക്കണിനായി കൈമാറ്റം ചെയ്യുകയും ചെയ്യുന്നു.
- വർദ്ധിച്ച സുരക്ഷ: PKCE ഓതറൈസേഷൻ കോഡ് തടസ്സപ്പെടുത്തുന്ന ആക്രമണങ്ങളെ തടയുന്നു, ഇത് SPAS-കൾക്കും മൊബൈൽ ആപ്പുകൾക്കും അനുയോജ്യമാക്കുന്നു.
- ശുപാർശ ചെയ്യുന്ന സമീപനം: PKCE-യോടുകൂടിയ ഓതറൈസേഷൻ കോഡ് ഫ്ലോ ആധുനിക വെബ്, മൊബൈൽ ആപ്ലിക്കേഷനുകൾക്ക് പൊതുവെ ഏറ്റവും സുരക്ഷിതവും ശുപാർശ ചെയ്യുന്നതുമായ ഫ്ലോ ആണ്.
4. ക്ലയിന്റ് ക്രെഡൻഷ്യൽസ് ഫ്ലോ
വിവരണം: ക്ലയിന്റ് ഒരു ആക്സസ് ടോക്കൺ നേടുന്നതിന് അതിൻ്റെ സ്വന്തം ക്രെഡൻഷ്യലുകൾ (ക്ലയിന്റ് ഐഡി, ക്ലയിന്റ് സീക്രട്ട്) ഉപയോഗിച്ച് ഓതറൈസേഷൻ സെർവറുമായി നേരിട്ട് ഓതന്റിക്കേറ്റ് ചെയ്യുന്നു. ഉപയോഗ കേസുകൾ: ബാക്കെൻഡ് സേവനങ്ങൾ പരസ്പരം ആക്സസ് ചെയ്യുന്നത് പോലുള്ള മെഷീൻ-ടു-മെഷീൻ ആശയവിനിമയം. ഗുണങ്ങൾ: ബാക്കെൻഡ് സേവനങ്ങൾക്കായി ലളിതം. ദോഷങ്ങൾ: ഉപയോക്തൃ ഓതന്റിക്കേഷന് അനുയോജ്യമല്ല. ഉദാഹരണം: ഒരു ഡാറ്റാ പ്രോസസ്സിംഗ് സേവനം ഒരു ഡാറ്റാബേസ് സേവനം ആക്സസ് ചെയ്യുന്നു.
FastAPI-യിലെ നടപ്പിലാക്കൽ:
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from jose import JWTError, jwt
from datetime import datetime, timedelta
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# Dummy client database (replace with a real database in production)
clients = {
"client_id": {
"client_secret": "client_secret",
"scopes": ["read", "write"]
}
}
# Function to create access token
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# HTTP Basic Authentication scheme
security = HTTPBasic()
# Endpoint for token generation
@app.post("/token")
async def login(credentials: HTTPBasicCredentials = Depends(security)):
client = clients.get(credentials.username)
if not client:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect client ID or secret",
headers={"WWW-Authenticate": "Basic"},
)
if credentials.password != client["client_secret"]:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect client ID or secret",
headers={"WWW-Authenticate": "Basic"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": credentials.username, "scopes": client["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer"}
# Dependency to authenticate requests
async def get_current_client(token: str):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
client_id: str = payload.get("sub")
if client_id is None:
raise credentials_exception
except JWTError:
raise credentials_exception
client = clients.get(client_id)
if client is None:
raise credentials_exception
return client
async def get_current_active_client(current_client = Depends(get_current_client)):
return current_client
# Example protected endpoint
@app.get("/data")
async def read_data(current_client = Depends(get_current_active_client)):
return {"message": "Data accessed by client: " + current_client["client_secret"]}
വിശദീകരണം:
- HTTP അടിസ്ഥാന ഓതന്റിക്കേഷൻ: ക്ലയിന്റിനെ ഓതന്റിക്കേറ്റ് ചെയ്യാൻ ഞങ്ങൾ `fastapi.security.HTTPBasic` ഉപയോഗിക്കുന്നു.
- `/token` എൻഡ്പോയിന്റ്: ഈ എൻഡ്പോയിന്റ് ക്ലയിന്റ് ഓതന്റിക്കേഷൻ കൈകാര്യം ചെയ്യുന്നു. ഇത് ക്ലയിന്റ് ഐഡിയും സീക്രട്ടും സാധൂകരിക്കുന്നു, സാധുവാണെങ്കിൽ, ഒരു ആക്സസ് ടോക്കൺ നിർമ്മിക്കുന്നു.
- `get_current_client` ഡിപ്പൻഡൻസി: ഈ ഫംഗ്ഷൻ ആക്സസ് ടോക്കൺ പരിശോധിക്കുകയും ക്ലയിന്റിനെ വീണ്ടെടുക്കുകയും ചെയ്യുന്നു.
- `/data` എൻഡ്പോയിന്റ്: ഇതൊരു സംരക്ഷിത എൻഡ്പോയിന്റാണ്, ഇത് ആക്സസ് ചെയ്യാൻ സാധുവായ ഒരു ആക്സസ് ടോക്കൺ ആവശ്യമാണ്.
ടോക്കൺ റിഫ്രഷ്
അപഹരിക്കപ്പെട്ട ടോക്കണുകളുടെ സ്വാധീനം കുറയ്ക്കുന്നതിന് ആക്സസ് ടോക്കണുകൾക്ക് സാധാരണയായി കുറഞ്ഞ ആയുസ്സ് ഉണ്ടാകും. ഉപയോക്താവ് വീണ്ടും ഓതറൈസ് ചെയ്യാതെ പുതിയ ആക്സസ് ടോക്കണുകൾ നേടുന്നതിന് ഉപയോഗിക്കാവുന്ന ദീർഘകാല ക്രെഡൻഷ്യലുകളാണ് റിഫ്രഷ് ടോക്കണുകൾ.
നടപ്പിലാക്കൽ പരിഗണനകൾ:
- റിഫ്രഷ് ടോക്കണുകൾ സൂക്ഷിക്കൽ: റിഫ്രഷ് ടോക്കണുകൾ സുരക്ഷിതമായി സൂക്ഷിക്കണം, ഒരു ഡാറ്റാബേസിൽ എൻക്രിപ്റ്റ് ചെയ്ത നിലയിൽ സൂക്ഷിക്കുന്നതാണ് ഉത്തമം.
- റിഫ്രഷ് ടോക്കൺ എൻഡ്പോയിന്റ്: റിഫ്രഷ് ടോക്കൺ അഭ്യർത്ഥനകൾ കൈകാര്യം ചെയ്യാൻ ഒരു പ്രത്യേക എൻഡ്പോയിന്റ് (ഉദാഹരണത്തിന്, `/refresh_token`) ഉണ്ടാക്കുക.
- റിഫ്രഷ് ടോക്കണുകൾ റദ്ദാക്കൽ: റിഫ്രഷ് ടോക്കണുകൾ അപഹരിക്കപ്പെടുകയോ ആവശ്യമില്ലാതാവുകയോ ചെയ്താൽ അവ റദ്ദാക്കാനുള്ള ഒരു സംവിധാനം നടപ്പിലാക്കുക.
ഉദാഹരണം (പാസ്വേഡ് ഫ്ലോ ഉദാഹരണം വികസിപ്പിക്കുന്നു):
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
import secrets # For generating secure random strings
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
REFRESH_TOKEN_EXPIRE_DAYS = 30 # Longer lifetime for refresh tokens
# Password hashing configuration
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"hashed_password": pwd_context.hash("password123"),
"scopes": ["read", "write"],
"refresh_token": None # Store refresh token here
}
}
# Function to verify password (same as before)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
# Function to create access token (same as before)
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# Function to create refresh token
def create_refresh_token():
return secrets.token_urlsafe(32) # Generate a secure random string
# OAuth2 endpoint for token generation
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = users.get(form_data.username)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
if not verify_password(form_data.password, user["hashed_password"]):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
# Create refresh token and store it (securely in a database in real-world)
refresh_token = create_refresh_token()
user["refresh_token"] = refresh_token # Store it in the user object for now (INSECURE for production)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user["username"], "scopes": user["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer", "refresh_token": refresh_token}
# Endpoint for refreshing the access token
@app.post("/refresh_token")
async def refresh_access_token(refresh_token: str):
# Find user by refresh token (securely query the database)
user = next((user for user in users.values() if user["refresh_token"] == refresh_token), None)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid refresh token",
headers={"WWW-Authenticate": "Bearer"},
)
# Create a new access token
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user["username"], "scopes": user["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer"}
# Dependency to authenticate requests (same as before)
async def get_current_user(token: str):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = next((user for user in users.values() if user["username"] == username), None)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint (same as before)
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
പ്രധാനപ്പെട്ട സുരക്ഷാ കുറിപ്പുകൾ:
- റിഫ്രഷ് ടോക്കണുകൾ സൂക്ഷിക്കൽ: ഈ ഉദാഹരണത്തിൽ റിഫ്രഷ് ടോക്കൺ മെമ്മറിയിൽ (സുരക്ഷിതമല്ലാത്ത രീതിയിൽ) സൂക്ഷിക്കുന്നു. ഒരു പ്രൊഡക്ഷൻ എൻവയോൺമെന്റിൽ, റിഫ്രഷ് ടോക്കണുകൾ ഒരു ഡാറ്റാബേസിൽ സുരക്ഷിതമായി സൂക്ഷിക്കുക, എൻക്രിപ്റ്റ് ചെയ്യുന്നതാണ് അഭികാമ്യം.
- റിഫ്രഷ് ടോക്കൺ റൊട്ടേഷൻ: റിഫ്രഷ് ടോക്കൺ റൊട്ടേഷൻ നടപ്പിലാക്കുന്നത് പരിഗണിക്കുക. ഒരു റിഫ്രഷ് ടോക്കൺ ഉപയോഗിച്ച ശേഷം, ഒരു പുതിയ റിഫ്രഷ് ടോക്കൺ ഉണ്ടാക്കുകയും പഴയത് അസാധുവാക്കുകയും ചെയ്യുക. ഇത് അപഹരിക്കപ്പെട്ട റിഫ്രഷ് ടോക്കണുകളുടെ സ്വാധീനം കുറയ്ക്കുന്നു.
- ഓഡിറ്റിംഗ്: സംശയാസ്പദമായ പ്രവർത്തനങ്ങൾ കണ്ടെത്താൻ റിഫ്രഷ് ടോക്കൺ ഉപയോഗം ലോഗ് ചെയ്യുക.
സുരക്ഷാ മികച്ച സമ്പ്രദായങ്ങൾ
OAuth2 നടപ്പിലാക്കുന്നത് ആദ്യത്തെ ചുവടുവെപ്പ് മാത്രമാണ്. നിങ്ങളുടെ API-യും ഉപയോക്തൃ ഡാറ്റയും സംരക്ഷിക്കാൻ സുരക്ഷാ മികച്ച സമ്പ്രദായങ്ങൾ പാലിക്കേണ്ടത് അത്യാവശ്യമാണ്.
- HTTPS ഉപയോഗിക്കുക: ക്ലയിന്റ്, ഓതറൈസേഷൻ സെർവർ, വിഭവ സെർവർ എന്നിവ തമ്മിലുള്ള ആശയവിനിമയം എൻക്രിപ്റ്റ് ചെയ്യാൻ എപ്പോഴും HTTPS ഉപയോഗിക്കുക.
- ഇൻപുട്ട് സാധൂകരിക്കുക: ഇൻജക്ഷൻ ആക്രമണങ്ങൾ തടയുന്നതിന് എല്ലാ ഇൻപുട്ട് ഡാറ്റയും നന്നായി സാധൂകരിക്കുക.
- റേറ്റ് ലിമിറ്റിംഗ്: ബ്രൂട്ട്-ഫോഴ്സ് ആക്രമണങ്ങൾ തടയാൻ റേറ്റ് ലിമിറ്റിംഗ് നടപ്പിലാക്കുക.
- ഡിപ്പൻഡൻസികൾ പതിവായി അപ്ഡേറ്റ് ചെയ്യുക: സുരക്ഷാ പിഴവുകൾ പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ FastAPI ഫ്രെയിംവർക്കും എല്ലാ ഡിപ്പൻഡൻസികളും കാലികമായി നിലനിർത്തുക.
- ശക്തമായ സീക്രട്ടുകൾ ഉപയോഗിക്കുക: നിങ്ങളുടെ ക്ലയിന്റ് സീക്രട്ടുകൾക്കും JWT സൈനിംഗ് കീകൾക്കും ശക്തവും റാൻഡം ആയ സീക്രട്ടുകൾ ഉണ്ടാക്കുക. ഈ സീക്രട്ടുകൾ സുരക്ഷിതമായി സൂക്ഷിക്കുക (ഉദാഹരണത്തിന്, എൻവയോൺമെന്റ് വേരിയബിളുകളോ ഒരു സീക്രട്ട്സ് മാനേജ്മെന്റ് സിസ്റ്റമോ ഉപയോഗിച്ച്).
- നിരീക്ഷിക്കുകയും ലോഗ് ചെയ്യുകയും ചെയ്യുക: സംശയാസ്പദമായ പ്രവർത്തനങ്ങൾക്കായി നിങ്ങളുടെ API നിരീക്ഷിക്കുകയും എല്ലാ ഓതന്റിക്കേഷൻ, ഓതറൈസേഷൻ ഇവന്റുകളും ലോഗ് ചെയ്യുകയും ചെയ്യുക.
- കുറഞ്ഞ പ്രിവിലേജ് നടപ്പിലാക്കുക: ക്ലയിന്റുകൾക്ക് ആവശ്യമായ അനുമതികൾ (സ്കോപ്പുകൾ) മാത്രം നൽകുക.
- കൃത്യമായ പിശക് കൈകാര്യം ചെയ്യൽ: പിശക് സന്ദേശങ്ങളിൽ സെൻസിറ്റീവ് വിവരങ്ങൾ വെളിപ്പെടുത്തുന്നത് ഒഴിവാക്കുക.
- നന്നായി പരിശോധിച്ച OAuth2 ലൈബ്രറി ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക: OAuth2 ആദ്യം മുതൽ നടപ്പിലാക്കുന്നതിനുപകരം, Authlib പോലുള്ള നന്നായി പരിശോധിച്ച ഒരു ലൈബ്രറി ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക. Authlib OAuth2-ന്റെ കൂടുതൽ കരുത്തുറ്റതും സുരക്ഷിതവുമായ ഒരു നടപ്പിലാക്കൽ നൽകുന്നു.
അടിസ്ഥാന കാര്യങ്ങൾക്കപ്പുറം: വികസിത പരിഗണനകൾ
നിങ്ങൾക്ക് ഒരു അടിസ്ഥാന OAuth2 നടപ്പിലാക്കൽ ഉണ്ടെങ്കിൽ, ഈ വികസിത വിഷയങ്ങൾ പരിഗണിക്കുക:
- സമ്മത മാനേജ്മെന്റ്: ഉപയോക്താക്കൾക്ക് അവർ ക്ലയിന്റുകൾക്ക് നൽകുന്ന അനുമതികളിൽ വ്യക്തവും സൂക്ഷ്മവുമായ നിയന്ത്രണം നൽകുക.
- ഡെലിഗേറ്റഡ് ഓതറൈസേഷൻ: ഉപയോക്താക്കൾക്ക് അവരുടെ പേരിൽ പ്രവർത്തിക്കാൻ ക്ലയിന്റുകളെ ഓതറൈസ് ചെയ്യാൻ അനുവദിച്ചുകൊണ്ട് ഡെലിഗേറ്റഡ് ഓതറൈസേഷനുള്ള പിന്തുണ നടപ്പിലാക്കുക.
- മൾട്ടി-ഫാക്ടർ ഓതന്റിക്കേഷൻ (MFA): സുരക്ഷ വർദ്ധിപ്പിക്കുന്നതിന് MFA സംയോജിപ്പിക്കുക.
- ഫെഡറേറ്റഡ് ഐഡന്റിറ്റി: മൂന്നാം കക്ഷി ഐഡന്റിറ്റി പ്രൊവൈഡർമാർ വഴി ഓതന്റിക്കേഷനെ പിന്തുണയ്ക്കുക (ഉദാഹരണത്തിന്, Google, Facebook, Twitter).
- ഡൈനാമിക് ക്ലയിന്റ് രജിസ്ട്രേഷൻ: ക്ലയിന്റുകൾക്ക് നിങ്ങളുടെ ഓതറൈസേഷൻ സെർവറിൽ സ്വയം ഡൈനാമിക്കായി രജിസ്റ്റർ ചെയ്യാൻ അനുവദിക്കുക.
ഉപസംഹാരം
FastAPI ഉപയോഗിച്ച് OAuth2 ഓതന്റിക്കേഷൻ നടപ്പിലാക്കുന്നത് നിങ്ങളുടെ API-കൾ സുരക്ഷിതമാക്കാനും ഉപയോക്തൃ ഡാറ്റ സംരക്ഷിക്കാനുമുള്ള ഒരു ശക്തമായ മാർഗ്ഗമാണ്. വ്യത്യസ്ത OAuth2 ഫ്ലോകൾ മനസ്സിലാക്കുന്നതിലൂടെയും, സുരക്ഷാ മികച്ച സമ്പ്രദായങ്ങൾ നടപ്പിലാക്കുന്നതിലൂടെയും, വികസിത വിഷയങ്ങൾ പരിഗണിക്കുന്നതിലൂടെയും, നിങ്ങളുടെ ഉപയോക്താക്കളുടെയും ആപ്ലിക്കേഷനുകളുടെയും ആവശ്യങ്ങൾ നിറവേറ്റുന്ന കരുത്തുറ്റതും സുരക്ഷിതവുമായ API-കൾ നിർമ്മിക്കാൻ നിങ്ങൾക്ക് കഴിയും. നിങ്ങളുടെ നിർദ്ദിഷ്ട ഉപയോഗ കേസിന് അനുയോജ്യമായ ഫ്ലോ തിരഞ്ഞെടുക്കാനും, സുരക്ഷയ്ക്ക് മുൻഗണന നൽകാനും, നിങ്ങളുടെ ഓതന്റിക്കേഷൻ സിസ്റ്റം തുടർച്ചയായി നിരീക്ഷിക്കുകയും മെച്ചപ്പെടുത്തുകയും ചെയ്യാനും ഓർക്കുക. നൽകിയിട്ടുള്ള ഉദാഹരണങ്ങൾ അടിസ്ഥാന തത്വങ്ങൾ പ്രദർശിപ്പിക്കുന്നുണ്ടെങ്കിലും, അവ നിങ്ങളുടെ നിർദ്ദിഷ്ട ആവശ്യകതകളുമായി എപ്പോഴും പൊരുത്തപ്പെടുത്തുകയും സമഗ്രമായ ഒരു അവലോകനത്തിനായി സുരക്ഷാ വിദഗ്ദ്ധരുമായി ബന്ധപ്പെടുകയും ചെയ്യുക.